import {
  Component,
  OnInit,
  AfterViewInit,
  OnDestroy,
  ViewChild,
  ElementRef,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  forwardRef
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { BACKSPACE } from '@angular/cdk/keycodes';
import { fromEvent, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/internal/operators';

const CODE_LEN = 4;

@Component({
  selector: 'app-wyy-code',
  templateUrl: './wyy-code.component.html',
  styleUrls: ['./wyy-code.component.less'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => WyyCodeComponent),
      multi: true
    }
  ]
})

export class WyyCodeComponent implements OnInit, AfterViewInit, OnDestroy, ControlValueAccessor {
  inputList = [];
  inputEle: HTMLElement[];
  result: string[] = [];
  currentFocusingIndex = 0;
  private code: string;
  private destroy$ = new Subject();
  @ViewChild('codeWrap', { static: true }) private codeWrap: ElementRef;
  constructor(private cdr: ChangeDetectorRef) {
    this.inputList = Array(CODE_LEN).fill('');
  }

  ngOnInit() {
  }
  ngAfterViewInit() {
    const inputArr = this.codeWrap.nativeElement.getElementsByClassName('item') as HTMLElement[];
    this.inputEle = inputArr;
    this.inputEle[0].focus();
    for (let a = 0; a < this.inputEle.length; a++) {
      const item = this.inputEle[a];
      fromEvent(item, 'keyup').pipe(takeUntil(this.destroy$)).subscribe((event: KeyboardEvent) => this.listenKeyUp(event));
      fromEvent(item, 'click').pipe(takeUntil(this.destroy$)).subscribe(() => this.currentFocusingIndex = a);
    }
  }
  private listenKeyUp(event: KeyboardEvent) {
    const target = event.target as HTMLInputElement;
    const keyCode = Number(event.key);
    const isBackSpace = keyCode === BACKSPACE;
    // 禁止输入非数字
    if (/\D/.test(target.value)) {
      target.value = '';
      this.result[this.currentFocusingIndex] = '';
    } else if (target.value) {
      this.result[this.currentFocusingIndex] = target.value;
      this.currentFocusingIndex = (this.currentFocusingIndex + 1) % CODE_LEN;
      this.inputEle[this.currentFocusingIndex].focus();
    } else if (isBackSpace) {
      this.result[this.currentFocusingIndex] = '';
      this.currentFocusingIndex = Math.max(this.currentFocusingIndex - 1, 0);
      this.inputEle[this.currentFocusingIndex].focus();
    }
    this.checkResult(this.result);
  }
  private setValue(code: string) {
    this.code = code;
    this.onValueChange(code);
    // 手动触发变更检测
    this.cdr.markForCheck();
  }
  private checkResult(result: string[]) {
    const codeStr = result.join('');
    this.setValue(codeStr);
  }
  private onValueChange(value: string): void {
    // console.log('value:', value);
  }
  private onValueTouched(): void {}
  registerOnChange(fn: (value: string) => void): void {
    this.onValueChange = fn;
  }
  registerOnTouched(fn: () => void): void {
    this.onValueTouched = fn;
  }
  writeValue(code: string) {
    this.setValue(code);
  }
  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}
